
// === uuMeta.url ===
// depend: uuMeta
/*
uuMeta.url.abs(url, curtdir) - return absolute URL
uuMeta.url.dir(abspath, result) - return absolute directory
uuMeta.url.parse(url) - return { url, scheme, domain, port, base, path,
                            dir, file, query, hash, fragment }
uuMeta.url.build(url) - return "scheme://domain:port/path?query#fragment"
uuMeta.url.parseQuery(query) - return { key: value, ... }
uuMeta.url.buildQuery(query) - return "key=value&key=value..."
 */
(function uuMetaURLScope() {
var _JUDGE_SCHEME = /^(file|https?):/,
    _PICKUP_HREF = /href\="([^"]+)"/,
    _TRIM_PATH = /^.*\?/,
    _AMP_DECODE = /&amp;/g,
    _SPLIT_QUERY_STRING = /(?:([^\=]+)\=([^\&]+)&?)/g,
    // file:///localhost/dir/file.ext
    _FILE = /^file:\/\/(?:\/)?(?:localhost\/)?((?:[a-z]:)?.*)$/i,
    // http://wwww.example.com:8080/dir/file.ext?key1=value1&key2=value2#frag
    _URL = /^([\w.+-]*):\/\/([^\/:]+)(?::(\d*))?([^ ?#]*)(?:\?([^#]*))?(?:#(.*))?/i;

// uuMeta.url.abs - convert relative URL to absolute URL
function urlAbs(url,       // @param URLString: rel/abs URL
                curtdir) { // @param URLString(= ""): current dir
                           // @return URLString: absolute URL
  if (!_JUDGE_SCHEME.test(url)) {
    var div = document.createElement("div");

    div.innerHTML = '<a href="' + (curtdir || "") + url + '" />';
    url = div.firstChild ? div.firstChild.href
                         : _PICKUP_HREF.exec(div.innerHTML)[1];
  }
  return url;
}

// uuMeta.url.dir - absolute path to absolute directory(chop filename)
//    dir("http://example.com/dir/file.ext") -> "http://example.com/dir/"
//    dir("/root/dir/file.ext")              -> "/root/dir/"
//    dir("/file.ext")                       -> "/"
//    dir("/")                               -> "/"
//    dir("")                                -> "/"
function urlDir(abspath,   // @param URLString/PathString: absolute path
                result) {  // @param Array(= undefined): ref result array
                           //                            ["dir/", "file.ext"]
                           // @return String: absolute directory path,
                           //                 has tail "/"
  result = result || [];
  var ary = abspath.split("/");

  result[1] = ary.pop(); // file
  result[0] = ary.join("/") + "/";
  return result[0]; // return dir
}

// uuMeta.url.parse - parse URL
//    uuMeta.url.parse(".") is current url
function urlParse(url) { // @param URLString:
                         // @return Boolean/Hash:
                         //           false is fail,
                         //           Hash( { url, scheme, domain, port, base,
                         //                   path, dir, file, query, hash,
                         //                   fragment } )
  var m, ary = ["/", ""], abs = urlAbs(url);

  if ( (m = _FILE.exec(abs)) ) {
    urlDir(m[1], ary);
    return {
      url: abs, scheme: "file", domain: "", port: "",
      base: "file:///" + ary[0], path: m[1], dir: ary[0],
      file: ary[1], query: "", hash: {}, fragment: ""
    };
  }
  if ( (m = _URL.exec(abs)) ) {
    m[4] && urlDir(m[4], ary);
    return {
      url:    abs,          // AbsoluteURLString( "http://..." )
      scheme: m[1],         // SchemeString( "file" or "http" or "https" )
      domain: m[2],         // DomainNameString( "www.example.com" )
      port:   m[3] || "",   // PortNumber( "8080" or "" ) - not Number
      base:   (m[1] + "://" + m[2]) + (m[3] ? ":" + m[3] : "") + ary[0],
      path:   m[4] || "/",  // PathString( "/dir/file.ext" or "/" )
      dir:    ary[0],       // DirString( "/dir" or "/" )
      file:   ary[1],       // FileNameString( "file.ext" or "" )
      query:  m[5] || "",   // QueryString( "key1=value1&key2=value2" or "" )
      hash:   m[5] ? urlParseQuery(m[5]) : {},
                            // QueryHash( { key1: "value1", key2: "value2" } )
      fragment: m[6] || ""  // FragmentString( "menu1" or "" )
    };
  }
  return false;
}

// uuMeta.url.build - build URL
function urlBuild(hash) { // @param Hash:
                          // @return String:
                          //         "scheme://domain:port/path?query#fragment"
  return [hash.scheme, "://", hash.domain,
          hash.port     ? ":" + hash.port     : "", hash.path || "/",
          hash.query    ? "?" + hash.query    : "",
          hash.fragment ? "#" + hash.fragment : ""].join("");
}

// uuMeta.url.parseQuery - parse QueryString
function urlParseQuery(query) { // @param QueryString:
                                // @return Hash: { key: value, ... }
  var rv = {},
      // alias
      fn = decodeURIComponent;

  query.replace(_TRIM_PATH, "").replace(_AMP_DECODE, "&").
        replace(_SPLIT_QUERY_STRING, function(m, key, value) {
    return rv[fn(key)] = fn(value);
  });
  return rv;
}

// uuMeta.url.buildQuery - build QueryString
function urlBuildQuery(query) { // @param Hash:
                                // @return QueryString: "key=value&key=value..."
  var rv = [], i,
      // alias
      fn = encodeURIComponent;

  for (i in query) {
    rv.push(fn(i) + "=" + fn(query[i]));
  }
  return rv.join("&");
}

// --- initialize ---

// --- export ---
uuMeta.url = {
  abs: urlAbs,
  dir: urlDir,
  parse: urlParse,
  build: urlBuild,
  parseQuery: urlParseQuery,
  buildQuery: urlBuildQuery
};

})(); // uuMeta.url scope

